#include "account.hh"
#include <fstream>
#include <iomanip>
#include <ctime>
#include <sstream>

namespace MiniBank
{

    Transaction::Transaction(const std::string& type, double amount, const std::string& note) : transactionType(type), transactionAmount(amount), transactionNote(note) 
    {
        //生成新ID
        transactionID = generateTransactionID();
    }

    std::string Transaction::getType() const 
    {
        return transactionType;
    }

    double Transaction::getAmount() const 
    {
        return transactionAmount;
    }

    std::string Transaction::getNote() const 
    {
        return transactionNote;
    }

    std::string Transaction::getTransactionID() const 
    {
        return transactionID;
    }

    std::string Transaction::generateTransactionID() 
    {
        static int counter = 0;   //函数结束不会销毁
        std::stringstream ss;
        ss << "T" << std::setfill('0') << std::setw(3) << counter++; //设置字宽为3，不足的部分在前用0填充
        return ss.str();
    }

    Account::Account(const std::string& id, const std::string& holder, double initialBalance) : accountID(id), accountHolder(holder), balance(initialBalance) {}

    Account::~Account() { }

    std::string Account::getAccountID() const 
    {
        return accountID;
    }

    std::string Account::getAccountHolder() const 
    {
        return accountHolder;
    }

    double Account::getBalance() const 
    {
        return balance;
    }

    const std::vector<Transaction>& Account::getTransactions() const 
    {
        return transactions;
    }

    void Account::deposit(double amount, const std::string& note) 
    {
        if (amount > 0) 
        {
            balance += amount;
            Transaction v1 = Transaction("Deposit", amount, note);
            transactions.push_back(v1);
            std::cout << "Deposit successful!" << std::endl;
            std::cout << "New balance: $" << balance << std::endl;
            std::cout << "Transaction ID: " << transactions.back().getTransactionID() << " has been recorded." << std::endl;
        }
        else 
        {
            std::cout << "Invalid deposit amount." << std::endl;
        }
    }

    bool Account::withdraw(double amount, const std::string& note) 
    {
        if (amount > 0 && balance >= amount) {
            balance -= amount;
            Transaction v1 = Transaction("Withdrawal", amount, note);
            transactions.push_back(v1);
            std::cout << "Withdrawal successful!" << std::endl;
            std::cout << "New balance: $" << balance << std::endl;
            std::cout << "Transaction ID: " << transactions.back().getTransactionID() << " has been recorded." << std::endl;
            return true;
        }
        else {
            std::cout << "Insufficient funds or invalid withdrawal amount." << std::endl;
            return false;
        }
    }

    //转账
    bool Account::transfer(Account& target, double amount, const std::string& note) 
    {
        if (amount > 0 && balance >= amount) 
        {
            balance -= amount;
            target.deposit(amount, note);
            Transaction v1 = Transaction("Transfer Out", amount, note);
            transactions.push_back(v1);
            std::cout << "Transfer successful!" << std::endl;
            std::cout << "New balance: $" << balance << std::endl;
            std::cout << "Transaction ID: " << transactions.back().getTransactionID() << " has been recorded." << std::endl;
            return true;
        }
        else 
        {
            std::cout << "Insufficient funds or invalid transfer amount." << std::endl;
            return false;
        }
    }

    void Account::displayInfo() const 
    {
        std::cout << "Account ID: " << accountID << std::endl;
        std::cout << "Account holder: " << accountHolder << std::endl;
        std::cout << "Balance: $" << balance << std::endl;
    }

    void Account::generateReport(const std::string& filename) const 
    {
        std::ofstream file(filename);  //用于写入文件
        if (file.is_open()) 
        {
            file << "Transaction Report for Account: " << accountID << std::endl;
            file << "----------------------------------------" << std::endl;
            for (const auto& transaction : transactions) 
            {
                file << "Type: " << transaction.getType() << ", Amount: $" << transaction.getAmount()
                     << ", Note: " << transaction.getNote() << ", ID: " << transaction.getTransactionID() << std::endl;
            }
            file.close();
            std::cout << "Report successfully generated as \"" << filename << "\"" << std::endl;   // \"表示双引号本身
        }
        else 
        {
            std::cout << "Unable to open file for report generation." << std::endl;
        }
    }

    //Deposit
    Account& Account::operator+=(double amount) 
    {
        deposit(amount);
        return *this;
    }

    //Withdraw
    Account& Account::operator-=(double amount) 
    {
        withdraw(amount);
        return *this;
    }

    SavingsAccount::SavingsAccount(const std::string& id, const std::string& holder, double initialBalance) : Account(id, holder, initialBalance) {}

    bool SavingsAccount::transfer(Account& target, double amount, const std::string& note) 
    {
        return Account::transfer(target, amount, note);
    }

    void SavingsAccount::displayInfo() const 
    {
        std::cout << "Savings Account: " << accountID << std::endl;
        Account::displayInfo();
    }

    CheckingAccount::CheckingAccount(const std::string& id, const std::string& holder, double initialBalance) : Account(id, holder, initialBalance) {}

    void CheckingAccount::deposit(double amount, const std::string& note) 
    {
        Account::deposit(amount, note);
    }

    bool CheckingAccount::withdraw(double amount, const std::string& note) 
    {
        return Account::withdraw(amount, note);
    }

    bool CheckingAccount::transfer(Account& target, double amount, const std::string& note) 
    {
        return Account::transfer(target, amount, note);
    }

    void CheckingAccount::displayInfo() const 
    {
        std::cout << "Checking Account: " << accountID << std::endl;
        Account::displayInfo();
    }

} 